<script setup lang="ts">
import {
  useMessage,
  NForm,
  NFormItem,
  NInput,
  NSelect,
  type FormInst,
  NButton,
  NDatePicker,
  NTreeSelect,
  NIcon,
  type TreeSelectOption,
  NConfigProvider,
  NAvatar,
  NUpload,
  type UploadCustomRequestOptions,
  type UploadInst,
  type FormRules,
  type FormItemRule,
  NDivider
} from 'naive-ui'
import { CheckmarkCircle, CloseCircle } from '@vicons/ionicons5'
import { onMounted, ref, shallowRef, toRaw } from 'vue'
import { sendRequest } from '@/utils/api'
import type { UserInfoModel, UserPositionModel, PartyOrganizationModel } from '@/api/user'
import type { HttpResponse } from '@/utils/http'
import FixedAction from '@/components/FixedAction.vue'
import useRouteParam from '@/hooks/useRouteParam'
import type { InstitutionTreeModel } from '@/api/sysInstitution'
import type { PositionTableRowModel } from '@/api/sysPosition'
import type { DicTreeModel } from '@/api/dic'
import { useRoute } from 'vue-router'
import { format } from 'date-fns'
import useRouteReplace from '@/hooks/useRouteReplace'
import validator from 'validator'
import { cloneDeep } from 'lodash-es'
import { cardNumberRegex } from '@/enums/regex'

const zuoJiExp = /^(?:(?:\d{3}-)?\d{8}|^(?:\d{4}-)?\d{7,8})(?:-\d+)?$/
const idNumberExp =
  /^[1-9][0-9]{5}(18|19|20)[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])[0-9]{3}([0-9]|X)$/
const formRules: FormRules = {
  mail: {
    trigger: ['blur', 'input'],
    validator: (_, value) => {
      if (!value) return true
      if (!validator.isEmail(value)) return new Error('请输入正确的邮箱格式')
      return true
    }
  },
  phone: {
    required: true,
    trigger: ['blur', 'input'],
    validator: (_, value) => {
      if (!value) return new Error('请输入手机号码')
      if (!validator.isMobilePhone(value, 'zh-CN')) return new Error('请输入正确的手机号码格式')
      return true
    }
  },
  officePhone: {
    trigger: ['blur', 'input'],
    validator: (_, value) => {
      if (!value) return true
      if (!zuoJiExp.test(value)) return new Error('办公电话格式有误')
      return true
    }
  },
  idNumber: {
    trigger: ['blur', 'input'],
    validator: (_, value) => {
      if (!value) return true
      if (!idNumberExp.test(value)) return new Error('请输入正确的身份证号格式')
      return true
    }
  },
  accountName: {
    required: false,
    trigger: ['input', 'blur'],
    validator: (_: any, value: any) => {
      // if (value?.length > 10) return new Error('开户名 字数不得超过10')
      return true
    }
  },
  openingBank: {
    required: false,
    trigger: ['input', 'blur'],
    validator: (_: any, value: any) => {
      // if (value?.length > 100) return new Error('开户行 字数不得超过100')
      return true
    }
  },
  bankCardNumber: {
    required: false,
    trigger: ['input', 'blur'],
    validator: (_: any, value: any) => {
      return true
    }
  }
}

type Nullable<T> = { [P in keyof T]: T[P] | null }

const message = useMessage()
const route = useRoute()
const routeReplace = useRouteReplace(route.query.redirect as string)
useRouteParam('id', () => queryUserInfo())

const formInst = shallowRef<FormInst | null>(null)
const formData = ref({} as UserInfoModel)
const submitLoading = ref(false)

const handleSubmit = () => {
  if (submitLoading.value) return
  formInst.value?.validate(async (error) => {
    if (error) return
    if (!userNumberPass.value) return

    try {
      submitLoading.value = true
      const rowF = cloneDeep(toRaw(formData.value))
      rowF.userPartyList.forEach((e) => {
        // @ts-ignore
        if (e.code === 'null') e.code = null
      })
      const [error, res] = await sendRequest<HttpResponse<UserInfoModel>>({
        module: 'user',
        api: 'update',
        override: {
          data: rowF
        }
      })

      if (error) throw error
      if (res.code !== 0) throw new Error(res.msg)
      message.success(res.msg)
      window.flags.flushUser = true
      routeReplace()
    } catch (error) {
      if (error instanceof Error) {
        message.error(error.message)
      }
    } finally {
      submitLoading.value = false
    }
  })
}

const userNumberPass = ref<boolean | null>(null)
const checkLoading = ref(false)
const checkUserNumber = async () => {
  if (!formData.value.userNumber) return (userNumberPass.value = null)
  try {
    checkLoading.value = true
    console.log(route)
    const [error, res] = await sendRequest<HttpResponse<boolean>>({
      module: 'user',
      api: 'checkUserNumber',
      override: {
        params: {
          userId: route.params.id as string,
          userNumber: formData.value.userNumber
        }
      }
    })
    if (error) throw error
    if (res.code !== 0) throw new Error(res.msg)
    userNumberPass.value = res.data
  } catch (error: any) {
    message.error(error.message)
  } finally {
    checkLoading.value = false
  }
}

// 职位列表
const handleUpdateDeptId = (value: number, index: number) => {
  deptOptions.value[index].deptId = value
  queryPositionList(value)
}
const positionList = ref(new Map<number, PositionTableRowModel[]>())
const queryPositionList = async (id: number) => {
  try {
    const [error, res] = await sendRequest<HttpResponse<PositionTableRowModel[]>>({
      module: 'sysPosition',
      api: 'listByDeptId',
      override: {
        params: {
          deptId: id,
          limit: 100000
        }
      }
    })

    if (error) return message.error(error.message)
    if (res.code !== 0) return message.error(res.msg)
    positionList.value.set(id, res.data)
  } catch (error) {
    console.log(error)
  }
}

// 部门列表
const treeOptions = shallowRef<InstitutionTreeModel[]>([])
const treeLoading = ref(false)
const queryTreeOptions = async () => {
  try {
    treeLoading.value = true
    const [error, res] = await sendRequest<HttpResponse<InstitutionTreeModel[]>>({
      module: 'sysInstitution',
      api: 'getTree'
    })

    if (error) return message.error(error.message)
    if (res.code !== 0) return message.error(res.msg)
    treeOptions.value = res.data[0] ? res.data[0].children ?? [] : []
  } catch (error) {
    console.log(error)
  } finally {
    treeLoading.value = false
  }
}
const deptOptions = ref<Nullable<Partial<UserPositionModel>>[]>([
  {
    deptId: null,
    positionId: null
  }
])
// @ts-ignore
formData.value.userPositionList = deptOptions.value
const handleAddDept = () => {
  deptOptions.value.push({
    deptId: null,
    positionId: null
  })
}
const handleDeleteDept = (index: number) => {
  deptOptions.value.splice(index, 1)
}

// 车牌号列表
const carNumberList = ref<(string | null)[]>([])
// @ts-ignore
formData.value.carNumberList = carNumberList.value
const handleAddCarNumber = () => {
  carNumberList.value.push(null)
}
const handleDeleteCarNumber = (index: number) => {
  carNumberList.value.splice(index, 1)
}

// 政治面貌
const politicalOptions = ref<DicTreeModel[] | undefined>()
const queryPoliticalOptions = async () => {
  const [error, res] = await sendRequest<HttpResponse<DicTreeModel[]>>({
    module: 'dic',
    api: 'getTree',
    override: {
      params: {
        dicCode: 'A22'
      }
    }
  })

  if (error) return message.error(error.message)
  if (res.code !== 0) return message.error(res.msg)
  politicalOptions.value = res.data[0]?.children
}

// 党职位
const partyPositionOptions = ref<DicTreeModel[] | undefined>()
const queryPartyPositionOptions = async () => {
  const [error, res] = await sendRequest<HttpResponse<DicTreeModel[]>>({
    module: 'dic',
    api: 'getTree',
    override: {
      params: {
        dicCode: 'A18'
      }
    }
  })

  if (error) return message.error(error.message)
  if (res.code !== 0) return message.error(res.msg)
  const tmp = res.data[0]?.children || []
  partyPositionOptions.value = [
    {
      // @ts-ignore
      code: 'null',
      name: ''
    },
    ...tmp
  ]
}
// 党组织
const partyOrganizationOptions = ref<DicTreeModel[] | undefined>()
const queryPartyOrganizationOptions = async () => {
  const [error, res] = await sendRequest<HttpResponse<DicTreeModel[]>>({
    module: 'dic',
    api: 'getTree',
    override: {
      params: {
        dicCode: 'A17'
      }
    }
  })

  if (error) return message.error(error.message)
  if (res.code !== 0) return message.error(res.msg)
  partyOrganizationOptions.value = res.data[0]?.children
}

const userPartyList = ref<Nullable<Partial<PartyOrganizationModel>>[]>([])
// @ts-ignore
formData.value.userPartyList = userPartyList.value
const handleAddPartyOrganization = () => {
  userPartyList.value.push({
    partyOrganizationCode: null,
    partyPositionCode: null
  })
}
const handleDeletePartyOrganization = (index: number) => {
  userPartyList.value.splice(index, 1)
}

const uploadInst = ref<UploadInst | null>(null)
const handleUpdateAvatar = async ({
  file,
  onFinish,
  onError,
  onProgress
}: UploadCustomRequestOptions) => {
  const form = new FormData()
  form.append('file', file.file as File)

  try {
    const [error, res] = await sendRequest({
      module: 'upload',
      api: 'uploadFile',
      override: {
        data: form,
        onUploadProgress({ progress }) {
          onProgress({ percent: progress || 0 })
        }
      }
    })
    if (error) throw error
    if (res.code !== 0) throw new Error(res.msg)
    formData.value.headSculpture = res.data.url
    onFinish()
  } catch (error: any) {
    onError()
    message.error(error.message)
  }
}

const queryUserInfo = async () => {
  const id = route.params.id as string

  formData.value = {} as UserInfoModel
  deptOptions.value = []
  carNumberList.value = []
  userPartyList.value = []

  try {
    const [error, res] = await sendRequest<HttpResponse<UserInfoModel>>({
      module: 'user',
      api: 'detailInfo',
      uri: {
        id: id
      }
    })
    if (error) return message.error(error.message)
    if (res.code !== 0) return message.error(res.msg)
    if (res.data.partyTime) res.data.partyTime = format(new Date(res.data.partyTime), 'yyyy-MM-dd')
    if (res.data.birthday) res.data.birthday = format(new Date(res.data.birthday), 'yyyy-MM-dd')
    formData.value = {
      ...res.data
    }
    deptOptions.value = res.data.userPositionList
    carNumberList.value = res.data.carNumberList
    userPartyList.value = res.data.userPartyList
    res.data.userPositionList.forEach((e) => e.deptId && queryPositionList(e.deptId!))
    checkUserNumber()
  } catch (error) {
    console.log(error)
  }
}

const limitRule: FormItemRule = {
  trigger: ['blur', 'input'],
  validator: (_, value) => {
    return value ? value.length <= 100 : true
  },
  message: '字符长度不能大于100'
}

onMounted(() => {
  queryTreeOptions()
  queryPoliticalOptions()
  queryPartyPositionOptions()
  queryPartyOrganizationOptions()
  queryUserInfo()
})
</script>

<template>
  <NConfigProvider
    abstract
    :theme-overrides="{
      Form: {
        labelTextColor: 'rgba(0,0,0,0.85)'
      }
    }"
  >
    <div class="add-user">
      <div class="form">
        <NForm
          :rules="formRules"
          :disabled="submitLoading"
          :model="formData"
          ref="formInst"
          label-placement="left"
          require-mark-placement="left"
          label-width="100rem"
        >
          <div class="with-avatar">
            <NFormItem
              label="姓名："
              class="name"
              path="userName"
              :rule="[{ required: true, message: '姓名为必填项，请输入' }, limitRule]"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.userName"
              />
            </NFormItem>
            <NFormItem
              label="性别："
              class="sex"
            >
              <NSelect
                v-model:value="formData.sex"
                :options="[
                  {
                    label: '男',
                    value: 1
                  },
                  {
                    label: '女',
                    value: 2
                  }
                ]"
              />
            </NFormItem>

            <NFormItem
              label="生日："
              class="birthday"
            >
              <NDatePicker
                input-readonly
                value-format="yyyy-MM-dd"
                v-model:formatted-value="formData.birthday"
              />
            </NFormItem>

            <div class="avatar">
              <NAvatar
                :src="formData.headSculpture"
                :size="150"
              />

              <NUpload
                ref="uploadInst"
                :custom-request="handleUpdateAvatar"
                :accept="'image/*'"
                :max="1"
                abstract
              >
                <NButton
                  ghost
                  color="#5FB17F"
                  @click="uploadInst?.openOpenFileDialog()"
                >
                  修改头像
                </NButton>
              </NUpload>
            </div>
          </div>
          <div class="col2">
            <NFormItem
              label="电子邮箱："
              path="mail"
              :rule="limitRule"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.mail"
              />
            </NFormItem>

            <NFormItem
              label="员工编号："
              path="userNumber"
              :rule="[{ required: true, message: '员工编号为必填项，请输入' }, limitRule]"
            >
              <NInput
                placeholder="请输入"
                @blur="() => checkUserNumber()"
                v-model:value="formData.userNumber"
                :loading="checkLoading"
              >
                <template
                  v-if="userNumberPass !== null"
                  #suffix
                >
                  <span
                    :style="`display:inline-flex; align-items: center; color: ${
                      userNumberPass ? '#5FB17F' : '#fd4a29'
                    }`"
                  >
                    <NIcon size="18rem">
                      <CheckmarkCircle v-if="userNumberPass" />
                      <CloseCircle v-else />
                    </NIcon>
                    <span>{{ userNumberPass ? '可以使用' : '不能使用' }}</span>
                  </span>
                </template>
              </NInput>
            </NFormItem>
            <NFormItem
              label="办公电话："
              path="officePhone"
              :rule="limitRule"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.officePhone"
              />
            </NFormItem>
            <NFormItem
              label="手机号码："
              path="phone"
              :rule="[{ required: true, message: '手机号码为必填项，请输入' }, limitRule]"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.phone"
              />
            </NFormItem>

            <NFormItem
              label="身份证号："
              path="idNumber"
              :rule="limitRule"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.idNumber"
              />
            </NFormItem>
            <NFormItem
              label="联系地址："
              path="contactAddress"
              :rule="limitRule"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.contactAddress"
              />
            </NFormItem>
            <NFormItem
              label="职称："
              path="positionalTitles"
              :rule="limitRule"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.positionalTitles"
              />
            </NFormItem>
          </div>
          <NDivider
            title-placement="left"
            style="--n-color: #5fb17f"
          >
            公务卡
          </NDivider>
          <div class="col2">
            <NFormItem
              label="开户名："
              path="accountName"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.accountName"
              />
            </NFormItem>
            <NFormItem
              label="开户行："
              path="openingBank"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.openingBank"
              />
            </NFormItem>
            <NFormItem
              label="银行卡号："
              path="bankCardNumber"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.bankCardNumber"
              />
            </NFormItem>
          </div>
          <NDivider
            title-placement="left"
            style="--n-color: #5fb17f"
          >
            工资卡
          </NDivider>
          <div class="col2">
            <NFormItem
              label="开户名："
              path="payrollCardAccountName"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.payrollCardAccountName"
              />
            </NFormItem>
            <NFormItem
              label="开户行："
              path="payrollCardBank"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.payrollCardBank"
              />
            </NFormItem>
            <NFormItem
              label="银行卡号："
              path="payrollCardNumber"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.payrollCardNumber"
              />
            </NFormItem>
          </div>
          <NDivider
            title-placement="left"
            style="--n-color: #5fb17f"
          ></NDivider>
          <NFormItem
            label="部门职位："
            path="userPositionList"
            :rule="{
              required: true,
              message: '部门职位为必填项，请添加',
              type: 'array'
            }"
          >
            <NButton
              color="#6CB187"
              ghost
              @click="handleAddDept"
            >
              新增职位
            </NButton>
          </NFormItem>
          <div class="bg-wrapper">
            <div
              class="col2"
              v-for="(item, i) in deptOptions"
              :key="i"
            >
              <NFormItem
                label="部门："
                :path="`userPositionList[${i}].deptId`"
                :rule="{
                  required: true,
                  message: '部门为必填项，请输入',
                  type: 'number',
                  trigger: 'change'
                }"
              >
                <NTreeSelect
                  :options="(treeOptions as unknown as TreeSelectOption[])"
                  placeholder="请输入"
                  key-field="id"
                  label-field="name"
                  :value="item.deptId"
                  @update:value="(e) => handleUpdateDeptId(e, i)"
                />
              </NFormItem>
              <NFormItem
                label="职位："
                :path="`userPositionList[${i}].positionId`"
                :rule="{
                  required: true,
                  message: '职位为必填项，请输入',
                  type: 'number',
                  trigger: 'change'
                }"
              >
                <NTreeSelect
                  :options="(positionList.get(item.deptId!) as unknown as TreeSelectOption[])"
                  placeholder="请输入"
                  key-field="id"
                  label-field="positionName"
                  v-model:value="item.positionId"
                />
              </NFormItem>

              <div
                class="item-close"
                v-if="deptOptions.length > 1"
                @click="handleDeleteDept(i)"
              >
                <NIcon>
                  <CloseCircle />
                </NIcon>
              </div>
            </div>
          </div>

          <NFormItem label="车牌号：">
            <NButton
              color="#6CB187"
              ghost
              @click="handleAddCarNumber"
            >
              新增车牌号
            </NButton>
          </NFormItem>
          <div class="col2">
            <NFormItem
              label="车牌号："
              :path="`carNumberList[${i}]`"
              v-for="(_, i) in carNumberList"
              :key="i"
              :rule="limitRule"
            >
              <NInput
                placeholder="请输入"
                v-model:value="carNumberList[i]"
              >
                <template #suffix>
                  <NIcon
                    color="#fd4a29"
                    size="24rem"
                    style="cursor: pointer"
                    @click="handleDeleteCarNumber(i)"
                  >
                    <CloseCircle />
                  </NIcon>
                </template>
              </NInput>
            </NFormItem>
          </div>

          <NFormItem
            label="组织信息："
            :show-feedback="false"
          ></NFormItem>
          <div class="col2">
            <NFormItem label="政治面貌：">
              <NTreeSelect
                v-model:value="formData.politicalOutlookCode"
                :options="politicalOptions"
                key-field="code"
                label-field="name"
              />
            </NFormItem>
            <NFormItem label="入党时间：">
              <NDatePicker
                input-readonly
                v-model:formatted-value="formData.partyTime"
                value-format="yyyy-MM-dd"
              />
            </NFormItem>
          </div>
          <NFormItem :show-feedback="false">
            <NButton
              color="#6CB187"
              ghost
              style="margin: 0 0 1em 100rem"
              @click="handleAddPartyOrganization"
            >
              新增组织信息
            </NButton>
          </NFormItem>
          <div class="bg-wrapper">
            <div
              class="col2"
              v-for="(item, i) in userPartyList"
              :key="i"
            >
              <NFormItem label="党组织：">
                <NTreeSelect
                  :options="partyOrganizationOptions"
                  placeholder="请输入"
                  key-field="code"
                  label-field="name"
                  v-model:value="item.partyOrganizationCode"
                />
              </NFormItem>
              <NFormItem label="党职位：">
                <NTreeSelect
                  :options="partyPositionOptions"
                  placeholder="请输入"
                  key-field="code"
                  label-field="name"
                  v-model:value="item.partyPositionCode"
                />
              </NFormItem>

              <div
                class="item-close"
                v-if="userPartyList.length > 1"
                @click="handleDeletePartyOrganization(i)"
              >
                <NIcon>
                  <CloseCircle />
                </NIcon>
              </div>
            </div>
          </div>

          <!-- <span style="padding-left: 100rem">
            带
            <span style="color: #fd4a29">*</span>
            为必填项
          </span> -->
        </NForm>
      </div>
    </div>
  </NConfigProvider>

  <FixedAction>
    <div class="add-user-buttons">
      <NButton
        color="#999999"
        ghost
        :disabled="submitLoading"
        @click="routeReplace"
      >
        取消
      </NButton>

      <NButton
        color="#5FB17F"
        :disabled="submitLoading"
        :loading="submitLoading"
        @click="handleSubmit"
      >
        确定
      </NButton>
    </div>
  </FixedAction>
</template>

<style scoped lang="scss">
.add-user {
  flex: 1;
  padding: 25rem 56rem 110rem 36rem;

  .n-input,
  .n-tree-select,
  .n-date-picker,
  .n-select {
    width: 400rem;
  }

  .form {
    width: 100%;
    padding: 25rem 33rem 27rem 20rem;
    background-color: #ebeceb;

    .n-form {
      width: 70%;
      margin: 0 auto;
    }
  }

  .with-avatar {
    display: grid;
    grid-template-areas:
      'name avatar'
      'sex avatar'
      'birthday avatar';

    .name {
      grid-area: name;
    }

    .sex {
      grid-area: sex;
    }

    .birthday {
      grid-area: birthday;
    }

    .avatar {
      grid-area: avatar;
      align-self: center;
      justify-self: center;
      display: flex;
      align-items: flex-end;
      gap: 0 1em;
    }
  }

  .col2 {
    position: relative;
    display: grid;
    grid-template-columns: repeat(2, auto);
    gap: 0 60rem;

    .item-close {
      position: absolute;
      top: 5rem;
      right: -48rem;
      display: flex;
      align-items: center;
      font-size: 24rem;
      cursor: pointer;
      color: #fd4a29;
      transition: all ease-in-out 0.3s;

      &:hover {
        opacity: 0.8;
      }
    }
  }
}

.add-user-buttons {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0 16rem;

  .n-button {
    width: 100rem;
    height: 50rem;
  }
}
</style>
